// --------------------------------------------------------------------------------------------------------------------
// <copyright file="TaskbarButton.cs" company="Roman '4ux-nbIx' Novitsky">
//   Copyright (c) Roman '4ux-nbIx' Novitsky 2010
// </copyright>
// <summary>
//   Defines the TaskbarButton type.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace TaskbarButtons
{
  #region Namespace Imports

  using System.Drawing;
  using System.Globalization;
  using System.Xml.Serialization;

  using CSLib.Net.Annotations;
  using CSLib.Net.Diagnostics;

  using EnvDTE;

  using Microsoft.VisualStudio.CommandBars;
  using Microsoft.WindowsAPICodePack.Taskbar;

  #endregion


  /// <summary>
  /// Describes and manipulates the taskbar button.
  /// </summary>
  [UsedImplicitly(ImplicitUseKindFlags.Default, ImplicitUseTargetFlags.WithMembers)]
  public sealed class TaskbarButton
  {
    #region Constants and Fields

    private static readonly Icon _gearIcon = Resources.Gear;
    private ThumbnailToolbarButton _button;

    #endregion


    #region Constructors and Destructors

    /// <summary>
    /// Initializes a new instance of the <see cref="TaskbarButton"/> class.
    /// </summary>
    public TaskbarButton()
    {
      HideWhenDisabled = true;
    }


    /// <summary>
    /// Initializes a new instance of the <see cref="TaskbarButton"/> class.
    /// </summary>
    /// <param name="applicationObject">
    /// The application object.
    /// </param>
    /// <param name="menuItemPath">
    /// The menu item path.
    /// </param>
    public TaskbarButton([NotNull] DTE applicationObject, [NotNull] string menuItemPath)
    {
      Assert.ArgumentNotNull(applicationObject, "applicationObject");
      Assert.ArgumentNotNullOrWhiteSpace(menuItemPath, "menuItemPath");

      HideWhenDisabled = true;
      MenuItemPath = menuItemPath;
      Initialize(applicationObject);
    }

    #endregion


    #region Properties

    /// <summary>
    /// Gets the caption.
    /// </summary>
    /// <value>
    /// The caption.
    /// </value>
    public string Caption
    {
      get
      {
        return CommandBarButton != null ? CommandBarButton.GetCaption() : GetMissingMenuItemCaption();
      }
    }

    /// <summary>
    /// Gets or sets a value indicating whether to hide the button when its disabled.
    /// </summary>
    /// <value>
    /// <c>True</c> if the button should be hidden when disabled; otherwise, <c>false</c>.
    /// </value>
    public bool HideWhenDisabled
    {
      get;
      set;
    }

    /// <summary>
    /// Gets a value indicating whether this <see cref="TaskbarButton"/> is visible.
    /// </summary>
    /// <value>
    /// <c>True</c> if this <see cref="TaskbarButton"/> is visible; otherwise, <c>false</c>.
    /// </value>
    public bool IsVisible
    {
      get
      {
        if (CommandBarButton == null)
        {
          return false;
        }

        if (HideWhenDisabled && !CommandBarButton.Enabled)
        {
          return false;
        }

        return CommandBarButton.Visible;
      }
    }


    /// <summary>
    /// Gets or sets the menu item path.
    /// </summary>
    /// <value>
    /// The menu item path.
    /// </value>
    public string MenuItemPath
    {
      get;
      set;
    }

    /// <summary>
    /// Gets or sets the toolbar button.
    /// </summary>
    /// <value>
    /// The toolbar button.
    /// </value>
    [CanBeNull]
    [XmlIgnore]
    public ThumbnailToolbarButton ToolBarButton
    {
      get
      {
        return _button;
      }

      set
      {
        if (_button != null)
        {
          _button.Click -= ButtonClick;
        }

        _button = value;

        if (_button != null)
        {
          _button.Click += ButtonClick;
        }

        Update();
      }
    }


    /// <summary>
    /// Gets or sets the command bar button.
    /// </summary>
    /// <value>
    /// The command bar button.
    /// </value>
    private CommandBarButton CommandBarButton
    {
      get;
      set;
    }

    #endregion


    #region Public Methods

    /// <summary>
    /// Initializes the specified application object.
    /// </summary>
    /// <param name="applicationObject">
    /// The application object.
    /// </param>
    public void Initialize(DTE applicationObject)
    {
      CommandBarButton = applicationObject.GetCommandBarButton(MenuItemPath);
    }


    /// <summary>
    /// Returns a <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.
    /// </summary>
    /// <returns>
    /// A <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.
    /// </returns>
    /// <filterpriority>2</filterpriority>
    public override string ToString()
    {
      return Caption;
    }

    #endregion


    #region Methods

    /// <summary>
    /// Updates the taskbar button.
    /// </summary>
    internal void Update()
    {
      if (_button == null)
      {
        return;
      }

      if (CommandBarButton == null)
      {
        _button.Icon = _gearIcon;
        _button.Tooltip = GetMissingMenuItemCaption();
        _button.Enabled = false;
        _button.Visible = true;

        return;
      }

      _button.Tooltip = Caption;
      _button.Enabled = CommandBarButton.Enabled;
      _button.Visible = CommandBarButton.Visible;
      _button.Icon = CommandBarButton.GetIcon() ?? _gearIcon;
    }


    private void ButtonClick([NotNull] object sender, [NotNull] ThumbnailButtonClickedEventArgs e)
    {
      Assert.ArgumentNotNull(sender, "sender");
      Assert.ArgumentNotNull(e, "e");

      if (CommandBarButton != null)
      {
        CommandBarButton.Execute();
      }
    }


    private string GetMissingMenuItemCaption()
    {
      return string.Format(CultureInfo.InvariantCulture, Resources.TaskbarButtonCommandNotFoundCaption, MenuItemPath);
    }

    #endregion
  }
}